/**
   * 格式化时间
   * 
   * ------------- 日 ---------------
   * 
   * d	月份中的第几天，有前导零的 2 位数字	01 到 31
   * 
   * j	月份中的第几天，没有前导零	1 到 31
   * 
   * l（“L”的小写字母）	星期几，完整的文本格式	Sunday 到 Saturday
   * 
   * N	ISO-8601 格式数字表示的星期中的第几天	1（表示星期一）到 7（表示星期天）
   * 
   * z	年份中的第几天	0 到 365
   * 
   * ------------- 星期 --------------
   * 
   * W	ISO-8601 格式年份中的第几周，每周从星期一开始	例如：42（当年的第 42 周）
   * 
   * ------------- 月份 --------------
   * 
   * m	数字表示的月份，有前导零	01 到 12
   * 
   * n	数字表示的月份，没有前导零	1 到 12
   * 
   * t	指定的月份有几天	28 到 31
   * 
   * ------------- 年 ----------------
   * 
   * L	是否为闰年	如果是闰年为 1，否则为 0
   * 
   * Y	4 位数字完整表示的年份	例如：1999 或 2003
   * 
   * y	2 位数字表示的年份	例如：99 或 03
   * 
   * ------------- 时间 --------------
   * 
   * g	小时，12 小时格式，没有前导零	1 到 12
   * 
   * G	小时，24 小时格式，没有前导零	0 到 23
   * 
   * h	小时，12 小时格式，有前导零	01 到 12
   * 
   * H	小时，24 小时格式，有前导零	00 到 23
   * 
   * i	有前导零的分钟数	00 到 59>
   * 
   * s	秒数，有前导零	00 到 59>
   * 
   * u	毫秒 	示例: 654
   * 
   * @param {String} layout eg.Y-m-d H:i:s
   * @returns {String} 格式化后的时间
   */
export default function format(layout = '') {
  if (!layout) {
    layout = 'Y-m-d H:i:s'
  }
  if (typeof layout !== "string") {
    throw TypeError('参数layout必须是字符串类型')
  }
  return [...layout].map(char => {
    if (!formatChar.hasOwnProperty(char)) {
      return char
    }
    return formatChar[char](this)
  }).join('')
}

const formatChar = {
  /**
   * 月份中的第几天，有前导零的 2 位数字	01 到 31
   * @param {Date} t Time对象
   */
  d: (t) => {
    return t.UTC ? t.getUTCDate().toString(10).padStart(2, '0') : t.getDate().toString(10).padStart(2, '0')
  },

  /**
   * 月份中的第几天，没有前导零的数字	1 到 31
   * @param {Date} t 
   * @returns 
   */
  j: (t) => {
    return t.UTC ? t.getUTCDate() : t.getDate()
  },

  /**
   * l（“L”的小写字母）	星期几，完整的文本格式 周一 到 周日
   * @param {Date} t Time对象
   */
  l: (t) => {
    return '周' + ['日', '一', '二', '三', '四', '五', '六'][t.UTC ? t.getUTCDay() : t.getDay()]
  },

  /**
   * N	星期中的第几天	1（表示星期一）到 0（表示星期天）
   * @param {Date} t 
   * @returns {String|Number}
   */
  N: (t) => { return t.UTC ? t.getUTCDay() : t.getDay() },

  /**
   * z	年份中的第几天	0 到 365
   * @param {Date} t 
   * @returns {String}
   */
  z: (t) => {
    const month = formatChar.n(t)
    let days = 0
    for (let i = 1; i < month; i++) {
      if (typeof monthDays[i] === 'function') {
        days += monthDays[i](t)
      } else {
        days += monthDays[i]
      }
    }
    return days + formatChar.j(t)
  },

  /**
   * W	ISO-8601 格式年份中的第几周，每周从星期一开始	例如：42（当年的第 42 周）
   * @param {Date} t
   * @returns {String}
   */
  W: (t) => {
    const days = formatChar.z(t)
    const w = Math.floor(days / 7)
    const reminder = days % 7
    return reminder > 0 ? w + 1 : w
  },

  /**
   * m	数字表示的月份，有前导零	01 到 12
   * @param {Date} t 
   * @returns {String}
   */
  m: (t) => { return t.UTC ? t.getUTCMonth().toString(10).padStart(2, '0') : t.getMonth().toString(10).padStart(2, '0') },

  /**
   * n	数字表示的月份，没有前导零	1 到 12
   * @param {Date} t 
   * @returns {String}
   */
  n: (t) => { return t.UTC ? t.getUTCMonth() : t.getMonth() },

  /**
   * 指定的月份有几天	28 到 31
   * @param {Date} t
   * @returns {String}
   */
  t: (t) => {
    const month = formatChar.n(t)
    if (typeof monthDays[month] === 'function') {
      return monthDays[month](t)
    }
    return monthDays[month]
  },

  /**
   * L	是否为闰年	如果是闰年为 1，否则为 0
   * @param {Date} t 
   * @returns {String}
   */
  L: (t) => {
    return Number(t.isLeapYear())
  },

  /**
   * Y	4 位数字完整表示的年份	例如：1999 或 2003
   * @param {Date} t 
   * @returns {String}
   */
  Y: (t) => { return t.UTC ? t.getUTCFullYear() : t.getFullYear() },

  /**
   * 2 位数字表示的年份	例如：99 或 03
   * @param {Date} t 
   * @returns {String}
   */
  y: (t) => {
    const year = t.UTC ? t.getUTCFullYear() : t.getFullYear()
    return year.toString(10).substring(2)
  },

  /**
   * g	小时，12 小时格式，没有前导零	1 到 12
   * @param {Date} t 
   * @returns {String}
   */
  g: (t) => {
    const h = t.UTC ? t.getUTCHours() : t.getHours()
    return h > 12 ? (h - 12) : h
  },

  /**
   * G	小时，24 小时格式，没有前导零	0 到 23
   * @param {Date} t 
   * @returns {String}
   */
  G: (t) => { return t.UTC ? t.getUTCHours() : t.getHours() },

  /**
   * h	小时，12 小时格式，有前导零	01 到 12
   * @param {Date} t 
   * @returns {String}
   */
  h: (t) => {
    let h = t.UTC ? t.getUTCHours() : t.getHours()
    h = h > 12 ? (h - 12) : h
    return h.toString(10).padStart(2, '0')
  },

  /**
   * 小时，24 小时格式，有前导零	00 到 23
   * @param {Date} t 
   * @returns 
   */
  H: (t) => { return t.UTC ? t.getUTCHours().toString(10).padStart(2, '0') : t.getHours().toString(10).padStart(2, '0') },

  /**
   * 有前导零的分钟数	00 到 59>
   * @param {Date} t 
   * @returns 
   */
  i: (t) => { return t.UTC ? t.getUTCMinutes().toString(10).padStart(2, '0') : t.getMinutes().toString(10).padStart(2, '0') },

  /**
   * s	秒数，有前导零	00 到 59>
   * @param {Date} t 
   * @returns 
   */
  s: (t) => { return t.UTC ? t.getUTCSeconds().toString(10).padStart(2, '0') : t.getSeconds().toString(10).padStart(2, '0') },

  /**
   * u	毫秒 	示例: 654321
   * @param {Date} t 
   */
  u: (t) => { return t.UTC ? t.getUTCMilliseconds() : t.getMilliseconds() },
}

const monthDays = {
  1: 31,
  2: (t) => {
    return formatChar.L(t) ? 29 : 28
  },
  3: 31,
  4: 30,
  5: 31,
  6: 30,
  7: 31,
  8: 31,
  9: 30,
  10: 31,
  11: 30,
  12: 31
}



